/* 
 * File:   unit.h
 * Author: cow
 *
 * Created on March 19, 2011, 6:53 PM
 *
 * to do
 *  - add range to combat
 *  - set up storage that allows units to move about - done
 *  - movement must make correct checks - done
 *  - stat transfer - mostly done in unitgroup. gotta check it
 *  - stats affect combat - done
 *  - stats affect movement
 *  - add in ap - make stats effect ap useage
 *  - allow the lib to return a list of units whose ap > 0 - probably wont implement
 *  - include unit state: broken, siege, flank,
 *  - make concentrated fire effect cohesion
 *
 */

#ifndef _UNIT_H
#define	_UNIT_H


//prototypes---------------------------
namespace Units{
class batery;
class bullet;
class voley;
class subunit;
class unit;
class unitgroup;
class unitLib;
class sunitLib;
int selftest();
}
//defines------------------------------
namespace Units{
enum bateryType{
    foreward = 0,
    broadside,
    rear,
    artilery
};
enum direction{
    up = 0,
    left,
    right,
    down
};

//pseudo-stats
//only useable in unit------------
#define damBuff damBuffS(power())
#define shdBuff shdBuffS(power())
#define accBuff accBuffS(speed(), cohesion())
#define evaBuff evaBuffS(speed(), cohesion())
#define mveBuff mveBuffS(speed(), cohesion())
//--------------------------------

#define damBuffS(x) (powToDam(x))
#define shdBuffS(x) (powToShd(x))
#define accBuffS(x, y) (speedToAcc(x) + cohsnToAcc(y))
#define evaBuffS(x, y) (speedToEva(x) + cohsnToEva(y))
#define mveBuffS(x, y) (speedToMove(x) + cohsnToMove(y))

#define powToDam(x)    x
#define powToShd(x)    x/2
#define speedToAcc(x)  x/4
#define cohsnToAcc(x)  x
#define speedToEva(x)  x/2
#define cohsnToEva(x)  x
#define speedToMove(x) x
#define cohsnToMove(x) x/3

#define numBStats 5
#define numBats 4
#define sunitdeath(dam, arm, shd) \
    (((double(dam - shd) / arm) * 100) > rand()%100)
}
//includes-----------------------------
#include <stdlib.h>
#include <math.h>
#include <iostream>
#include <map>
#include <list>
#include <vector>
#include <string>
using namespace std;

//definitions--------------------------
namespace Units{
//bullet+++++++++++
class bullet{
public:
    bullet();
    bullet(bullet* copyme);
    int damage(int val);
    int damage();
    int accuracy(int val);
    int accuracy();
    int minRange(int val);
    int minRange();
    int maxRange(int val);
    int maxRange();
    int apCost(int val);
    int apCost();
    bullet* shoot();
    //comparator
    bool operator== (bullet& b);
private:
    int dam;
    int acc;
    int mxrange;
    int mnrange;
    int apcost;
};
//voley++++++++++++
class voley{
public:
    //constructor-------
    voley(int x, int y);
    //manips------------
    bullet* nextShot();
    void pushBullet(bullet* add);
    void pushBullet(bullet* add, int num);
    //stats-------------
    void buff(int dam, int acc);
    void source(int *x, int *y);
    int getX(){return sourcex;}
    int getY(){return sourcey;}
    int size();
    void print();
private:
    vector<bullet*> types;
    map<bullet*, int> rounds;
    int sourcex;
    int sourcey;
};
//subunit++++++++++
class subunit{
public:
    //constructors------
    subunit(int arm, int shd, int eva, int spd);
    ~subunit();
    void addBatery(bateryType btp, int dam = 0, int acc = 50,
                                    int mnr = 0, int mxr = 0, int ap = 1);
    bullet* gbattery(bateryType btp){return batery[btp];}
    //manips------------
    bullet* shoot(bateryType btp);
    int dead(int numshots, voley* vol, bool shield);
    //stats-------------
    int arm(){return armor;}
    int shd(){return shield;}
    int eva(){return evasion;}
    int spd(){return speed;}
protected:
private:
    int armor;
    int shield;
    int evasion;
    int speed;
    //fore, aft, broad, artilery
    bullet *batery[4];
};
//unit+++++++++++++
class unit{
public:
    //constructor-------
    unit();
    unit(unitLib* lib);
    ~unit();
    void owner(int o){ownerid = o;}
    int owner(){return ownerid;}
    void record(unitLib* rec = NULL);
    void add(subunit* su, int num);
    void remove(subunit* su, int num);
    void setParent(unitgroup* gp);
    //manips------------
    bool move(int mx, int my);
    bool place(int mx, int my);
    void face(direction facing);
    direction face();
    direction relation(int x, int y);
    //combat------------
    voley* shoot(int mx, int my, bateryType tp);
    bool useShield(int x, int y);
    void takeDamage(voley* vol);
    //ap----------------
    int apoints();
    bool useap(int u);
    void resetAP();
    //information-------
    void name(string str){strname = str;}
    string name(){return strname;}
    int posX(){return posx;}
    int posY(){return posy;}
    map<subunit*, int>::iterator unititer(){return subunitList.begin();}
    int sunits(){return subunitList.size();}
    int nums(subunit* su);
    //stats-------------
    bool dead();
    int speed(int buff = 0);
    int power(int buff = 0);
    int cohesion(int buff = 0);
protected:
private:
    //stats-------------
    string strname;
    bool amdead;
    int ownerid;
    int powerstat;
    int powerbuff;
    int speedstat;
    int speedbuff;
    int cohesionstat;
    int cohesionbuff;
    int ap;
    //pointers----------
    map<subunit*, int> subunitList;
    unitgroup* parent;
    unitLib* lib;
    //position----------
    direction facing;
    int posx;
    int posy;
};
//subunit++++++++++
class unitgroup{
public:
    //constructor-------
    unitgroup(unit* flag);
    ~unitgroup();
    //access------------
    int speedBuff(int set = -1);
    int powerBuff(int set = -1);
    int cohesionBuff(int set = -1);
    int numUnits();
    //inforamtion-------
    void name(string str){strname = str;}
    string name(){return strname;}
    list<unit*>::iterator unitIter(){return children.begin();}
    //unit manipulation-
    void addUnit(unit* u);
    void remUnit(unit* u);
private:
    string strname;
    int cohes;
    int power;
    int speed;
    unit* flagunit;
    list<unit*> children;
};
//unitlib++++++++++
class unitLib{
public:
    //constructors------
    static unitLib* staticLib();
    unitLib();
    ~unitLib();
    //manips------------
    void resetAP();
    void record(Units::unit* addme);
    void killUnit(Units::unit* killme);
    //access------------
    bool move(unit* un, int sx, int sy, int nx, int ny);
    unit* getUnit(int x, int y);
    bool addUnit(unit* nu, int x, int y);
    bool removeUnit(unit* u, int x, int y);
protected:
    static unitLib* slib;
    list<unit*> pieces;
    map<int, map< int, unit*> > unitmap;
};
//sunitlib+++++++++
}
#endif	/* _UNIT_H */

